#pragma once
struct FeatureNode 
{
  int index;
  double value;
  FeatureNode (int i, double v) : index(i), value(v) {}
};

struct Problem 
{
  vector<FeatureNode> xStore; // all feature nodes of problem
  vector<int> xStart; // start position of feature vector

  vector<double> y;  // label
  int n;             // dimension of problem
  
  void readInput(const string& fname);
  int size() const { return SIZE(y); }
};

struct LinearModel 
{
  vector<double> w;
  double bias;

  double output(const Problem& problem, int i) const;
  void save(const string& fname) const;
  void load(const string& fname);
};

class Pegasos 
{
public:
  mpi::communicator& world;
  po::variables_map& vm;
  po::options_description desc;

  Pegasos(mpi::communicator& world_, po::variables_map& vm_) 
    : world(world_), vm(vm_), desc("Allowed options") {}
  
  void processParameter(int argc, char* argv[]);
  void run();

  void doTrain();
  void doTest();
  void doCrossValidation();

  void train();
  double computeObjective() const;
public:
  LinearModel model;
  Problem problem;

  double lambda;
  int k;
  int max_iter;
  int verbose;
};
